<script setup lang="ts">
import { ref, onMounted, reactive, nextTick } from 'vue';
import * as echarts from 'echarts';
import { ElMessage } from 'element-plus';
import { getAttackPathData, saveAttackPathData } from '../api/attackPath';
import type { AttackPathData } from '../types/attackPath';

// 图表DOM引用
const chartContainer = ref<HTMLElement | null>(null);
const chartInstance = ref<echarts.ECharts | null>(null);

// 控制面板状态
const controlPanel = reactive({
  visible: false,
  nodeDetail: null as any,
  zoomRatio: 100,
  filterType: 'all',
  loading: false,
});

// 图表数据
const graphData = reactive<AttackPathData>({
  nodes: [],
  links: []
});

// 获取攻击路径数据
const fetchAttackPathData = async () => {
  controlPanel.loading = true;
  try {
    const data = await getAttackPathData();
    graphData.nodes = data.nodes;
    graphData.links = data.links;
    nextTick(() => {
      initChart();
    });
  } catch (error) {
    console.error('获取攻击路径数据失败:', error);
    ElMessage.error('获取攻击路径数据失败');
  } finally {
    controlPanel.loading = false;
  }
};

// 初始化图表
const initChart = () => {
  if (!chartContainer.value) return;
  
  // 销毁已有实例
  if (chartInstance.value) {
    chartInstance.value.dispose();
  }
  
  // 创建图表实例
  chartInstance.value = echarts.init(chartContainer.value);
  
  // 配置图表选项
  const option = {
    title: {
      text: '攻击路径可视化图谱',
      subtext: '展示攻击链关联关系',
      top: 'top',
      left: 'center'
    },
    tooltip: {
      trigger: 'item' as const,
      formatter: function(params: any) {
        if (params.dataType === 'node') {
          const data = params.data;
          const value = data.value;
          let content = `<div style="font-weight:bold;margin-bottom:5px;">${data.name}</div>`;
          
          if (value.type === 'ip') {
            content += `
              <div>类型: IP地址</div>
              <div>地理位置: ${value.location}</div>
              <div>风险等级: ${value.risk}</div>
              <div>描述: ${value.description}</div>
            `;
          } else if (value.type === 'domain') {
            content += `
              <div>类型: 域名</div>
              <div>注册商: ${value.registrar}</div>
              <div>风险等级: ${value.risk}</div>
              <div>描述: ${value.description}</div>
            `;
          } else if (value.type === 'file') {
            content += `
              <div>类型: 文件哈希</div>
              <div>文件类型: ${value.fileType}</div>
              <div>检测率: ${value.detection}</div>
              <div>风险等级: ${value.risk}</div>
              <div>描述: ${value.description}</div>
            `;
          }
          
          return content;
        } else if (params.dataType === 'edge') {
          return `<div>${params.data.source} <b>${params.data.value}</b> ${params.data.target}</div>`;
        }
        return '';
      }
    },
    legend: {
      data: ['IP地址', '域名', '文件哈希'],
      icon: 'circle',
      top: 'bottom',
      textStyle: {
        color: '#333'
      }
    },
    toolbox: {
      show: true,
      feature: {
        saveAsImage: { title: '保存图片' },
        restore: { title: '还原' },
        dataView: { title: '数据视图', readOnly: true }
      }
    },
    animationDuration: 1500,
    animationEasingUpdate: 'quinticInOut',
    series: [{
      name: '攻击路径',
      type: 'graph',
      layout: 'force',
      data: graphData.nodes as any[],
      links: graphData.links as any[],
      categories: [
        { name: 'IP地址' },
        { name: '域名' },
        { name: '文件哈希' }
      ],
      roam: true,
      draggable: true,
      label: {
        show: true,
        position: 'right',
        formatter: '{b}'
      },
      labelLayout: {
        hideOverlap: true
      },
      scaleLimit: {
        min: 0.1,
        max: 2
      },
      lineStyle: {
        color: 'source',
        curveness: 0.3
      },
      emphasis: {
        focus: 'adjacency',
        lineStyle: {
          width: 6
        }
      },
      force: {
        repulsion: 300,
        edgeLength: 150
      },
      edgeSymbol: ['none', 'arrow'],
      edgeLabel: {
        show: true,
        formatter: '{c}',
        fontSize: 12
      }
    }]
  };
  
  // 应用配置
  chartInstance.value.setOption(option as any);
  
  // 注册点击事件
  chartInstance.value.on('click', 'series.graph.nodes', (params: any) => {
    controlPanel.nodeDetail = params.data;
    controlPanel.visible = true;
  });
  
  // 注册缩放事件
  chartInstance.value.on('datazoom', () => {
    const zoom = chartInstance.value?.getOption().dataZoom;
    if (zoom && Array.isArray(zoom) && zoom.length > 0) {
      const start = zoom[0].start as number;
      const end = zoom[0].end as number;
      controlPanel.zoomRatio = Math.round((end - start) * 100);
    }
  });
};

// 处理窗口大小变化
const handleResize = () => {
  chartInstance.value?.resize();
};

// 过滤节点
const filterNodes = (type: string) => {
  controlPanel.filterType = type;
  
  if (!chartInstance.value) return;
  
  let filteredNodes = graphData.nodes;
  
  if (type !== 'all') {
    filteredNodes = graphData.nodes.filter(node => {
      if (type === 'ip' && node.category === 0) return true;
      if (type === 'domain' && node.category === 1) return true;
      if (type === 'file' && node.category === 2) return true;
      return false;
    });
  }
  
  const option = chartInstance.value.getOption();
  if (option.series && Array.isArray(option.series)) {
    (option.series[0] as any).data = filteredNodes;
    chartInstance.value.setOption(option);
  }
};

// 放大缩小
const zoom = (ratio: number) => {
  if (!chartInstance.value) return;
  
  controlPanel.zoomRatio = Math.max(10, Math.min(200, controlPanel.zoomRatio + ratio));
  
  // 通过dataZoom来模拟缩放效果
  chartInstance.value.dispatchAction({
    type: 'dataZoom',
    start: 0,
    end: controlPanel.zoomRatio / 100 * 100
  });
};

// 重置视图
const resetView = () => {
  fetchAttackPathData();
  controlPanel.zoomRatio = 100;
  controlPanel.filterType = 'all';
  ElMessage.success('视图已重置');
};

// 导出图片
const exportImage = () => {
  if (!chartInstance.value) return;
  
  const url = chartInstance.value.getDataURL({
    type: 'png',
    pixelRatio: 2,
    backgroundColor: '#fff'
  });
  
  const link = document.createElement('a');
  link.download = '攻击路径图谱_' + new Date().getTime() + '.png';
  link.href = url;
  link.click();
  
  ElMessage.success('图片已导出');
};

// 导出数据
const exportData = () => {
  const dataStr = JSON.stringify(graphData, null, 2);
  const blob = new Blob([dataStr], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  
  const link = document.createElement('a');
  link.download = '攻击路径数据_' + new Date().getTime() + '.json';
  link.href = url;
  link.click();
  
  URL.revokeObjectURL(url);
  ElMessage.success('数据已导出');
};

// 保存数据
const saveData = async () => {
  controlPanel.loading = true;
  try {
    await saveAttackPathData(graphData);
    ElMessage.success('数据保存成功');
  } catch (error) {
    console.error('保存数据失败:', error);
    ElMessage.error('保存数据失败');
  } finally {
    controlPanel.loading = false;
  }
};

// 生命周期钩子
onMounted(() => {
  fetchAttackPathData();
  window.addEventListener('resize', handleResize);
});
</script>

<template>
  <div class="attack-path-container">
    <div class="control-bar">
      <div class="filter-controls">
        <el-radio-group v-model="controlPanel.filterType" @change="filterNodes">
          <el-radio-button label="all">全部</el-radio-button>
          <el-radio-button label="ip">IP地址</el-radio-button>
          <el-radio-button label="domain">域名</el-radio-button>
          <el-radio-button label="file">文件哈希</el-radio-button>
        </el-radio-group>
      </div>
      
      <div class="zoom-controls">
        <el-button-group>
          <el-button @click="zoom(-10)" :icon="'ZoomOut'" size="small">缩小</el-button>
          <el-button>{{ controlPanel.zoomRatio }}%</el-button>
          <el-button @click="zoom(10)" :icon="'ZoomIn'" size="small">放大</el-button>
        </el-button-group>
      </div>
      
      <div class="action-controls">
        <el-button-group>
          <el-button @click="resetView" :icon="'Refresh'" size="small">重置视图</el-button>
          <el-button @click="exportImage" :icon="'Picture'" size="small">导出图片</el-button>
          <el-button @click="exportData" :icon="'Document'" size="small">导出数据</el-button>
          <el-button @click="saveData" :icon="'Upload'" size="small" type="primary">保存数据</el-button>
        </el-button-group>
      </div>
    </div>
    
    <div class="chart-wrapper">
      <div ref="chartContainer" class="chart-container"></div>
      <el-empty v-if="graphData.nodes.length === 0 && !controlPanel.loading" description="暂无数据" />
      <div v-if="controlPanel.loading" class="loading-overlay">
        <el-spinner size="large" />
        <p>加载中...</p>
      </div>
    </div>
    
    <el-drawer
      v-model="controlPanel.visible"
      title="节点详情"
      size="30%"
      direction="rtl"
    >
      <div v-if="controlPanel.nodeDetail" class="node-detail">
        <h2>{{ controlPanel.nodeDetail.name }}</h2>
        
        <el-descriptions :column="1" border>
          <el-descriptions-item v-if="controlPanel.nodeDetail.value.type === 'ip'" label="节点类型">
            <el-tag type="primary">IP地址</el-tag>
          </el-descriptions-item>
          <el-descriptions-item v-else-if="controlPanel.nodeDetail.value.type === 'domain'" label="节点类型">
            <el-tag type="success">域名</el-tag>
          </el-descriptions-item>
          <el-descriptions-item v-else-if="controlPanel.nodeDetail.value.type === 'file'" label="节点类型">
            <el-tag type="warning">文件哈希</el-tag>
          </el-descriptions-item>
          
          <!-- IP地址特有属性 -->
          <template v-if="controlPanel.nodeDetail.value.type === 'ip'">
            <el-descriptions-item label="地理位置">{{ controlPanel.nodeDetail.value.location }}</el-descriptions-item>
            <el-descriptions-item label="首次发现">{{ controlPanel.nodeDetail.value.firstSeen }}</el-descriptions-item>
            <el-descriptions-item label="最后活动">{{ controlPanel.nodeDetail.value.lastSeen }}</el-descriptions-item>
          </template>
          
          <!-- 域名特有属性 -->
          <template v-if="controlPanel.nodeDetail.value.type === 'domain'">
            <el-descriptions-item label="注册商">{{ controlPanel.nodeDetail.value.registrar }}</el-descriptions-item>
            <el-descriptions-item label="创建日期">{{ controlPanel.nodeDetail.value.created }}</el-descriptions-item>
            <el-descriptions-item label="过期日期">{{ controlPanel.nodeDetail.value.expires }}</el-descriptions-item>
          </template>
          
          <!-- 文件特有属性 -->
          <template v-if="controlPanel.nodeDetail.value.type === 'file'">
            <el-descriptions-item label="文件类型">{{ controlPanel.nodeDetail.value.fileType }}</el-descriptions-item>
            <el-descriptions-item label="文件大小">{{ controlPanel.nodeDetail.value.size }}</el-descriptions-item>
            <el-descriptions-item label="检测率">{{ controlPanel.nodeDetail.value.detection }}</el-descriptions-item>
          </template>
          
          <!-- 通用属性 -->
          <el-descriptions-item label="风险等级">
            <el-tag v-if="controlPanel.nodeDetail.value.risk === 'high'" type="danger">高</el-tag>
            <el-tag v-else-if="controlPanel.nodeDetail.value.risk === 'medium'" type="warning">中</el-tag>
            <el-tag v-else-if="controlPanel.nodeDetail.value.risk === 'low'" type="info">低</el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="描述">{{ controlPanel.nodeDetail.value.description }}</el-descriptions-item>
        </el-descriptions>
        
        <div class="related-nodes">
          <h3>关联节点</h3>
          <el-table :data="graphData.links.filter(link => 
            link.source === controlPanel.nodeDetail.id || link.target === controlPanel.nodeDetail.id
          )">
            <el-table-column label="关系" prop="value" />
            <el-table-column label="关联节点">
              <template #default="scope">
                {{ scope.row.source === controlPanel.nodeDetail.id ? 
                  graphData.nodes.find(n => n.id === scope.row.target)?.name : 
                  graphData.nodes.find(n => n.id === scope.row.source)?.name }}
              </template>
            </el-table-column>
            <el-table-column label="方向">
              <template #default="scope">
                {{ scope.row.source === controlPanel.nodeDetail.id ? '出站' : '入站' }}
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
    </el-drawer>
  </div>
</template>

<style scoped lang="scss">
.attack-path-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  background-color: #f5f7fa;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  
  .control-bar {
    padding: 16px;
    background-color: #fff;
    border-bottom: 1px solid #e4e7ed;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 16px;
    
    .filter-controls, .zoom-controls, .action-controls {
      display: flex;
      align-items: center;
    }
  }
  
  .chart-wrapper {
    flex: 1;
    position: relative;
    min-height: 600px;
    
    .chart-container {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
    }
    
    .loading-overlay {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(255, 255, 255, 0.7);
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      z-index: 10;
    }
  }
  
  .node-detail {
    padding: 16px;
    
    h2 {
      margin-top: 0;
      margin-bottom: 16px;
      word-break: break-all;
    }
    
    .related-nodes {
      margin-top: 24px;
    }
  }
}
</style>